Ext.define('PackageManager.model.PackageModelFull', {
    extend: 'Ext.data.Model',
    requires: ['PackageManager.model.Component', 'PackageManager.model.StaticData'],
    idProperty: 'id',
    fields: [
        {name: 'id', type: 'int'},
        {name: 'stage', type: 'string'}
    ],
    hasMany: [
        {model: 'PackageManager.model.Component',
            name: 'components',
            associationKey: 'components',
            foreignKey: 'id',
            storeConfig: {
                listeners: {
                    // Set parent object dirty if we added a new child.
                    add: function(store, records, index, opts) {
                        var obj = records[0]; // NOTE not fully general but works for our case!
                        if (obj.get('id') === 0) {
                            this.setParentDirty(obj.get('id_component'));
                        }
                    },
                    // Set parent object dirty if we removed an existing child
                    remove: function(store, obj, index, opts) {
                        if (obj.get('id') != 0) {
                            obj.parent.setDirty();
                        }
                    },
                    // Set parent object dirty if we updated an existing child
                    update: function(store, obj, index, opts) {
                        if (obj.get('id') != 0) {
                            obj.parent.setDirty();
                        }
                    }
                },
                setParentDirty: function(parent_id) {
                    var store = Ext.data.StoreManager.lookup('PackageStoreFull');
                    var pool = store.getById(parent_id);
                    if (parent) {
                        parent.setDirty();
                    }
                }
            }},
        {model: 'PackageManager.model.StaticData', name: 'staticDatas', associationKey: 'staticDatas'}
    ]
});

Ext.data.writer.Json.override({
    getRecordData: function(record, operation) {
        // Setup variables
        var me = this, i, association, childStore, data;
        data = me.callParent(arguments);
        // Iterate over all the hasMany associations
        for (i = 0; i < record.associations.length; i++) {
            association = record.associations.get(i);
            if (association.type == 'hasMany') {
                data[association.name] = null;
                childStore = record[association.storeName];
                // Iterate over all the children in the current
                // association
                childStore.each(function(childRecord) {
                    if (!data[association.name]) {
                        data[association.name] = [];
                    }
                    // Recursively get the record data for
                    // children (depth first)
                    var childData = this.getRecordData.call(
                        this, childRecord);
                    /*
                     * If the child was marked dirty or phantom
                     * it must be added. If there was data
                     * returned that was neither dirty or
                     * phantom, this means that the depth first
                     * recursion has detected that it has a
                     * child which is either dirty or phantom.
                     * For this child to be put into the
                     * prepared data, it's parents must be in
                     * place whether they were modified or not.
                     */
                    if (childRecord.dirty
                        || childRecord.phantom
                        || (childData != null)) {
                        data[association.name].push(childData);
                        record.setDirty();
                    }
                }, me);

                /*
                 * Iterate over all the removed records and add them to
                 * the preparedData. Set a flag on them to show that
                 * they are to be deleted
                 */
                Ext.each(childStore.removed, function(removedChildRecord) {
                    // Set a flag here to identify removed
                    // records
                    removedChildRecord.set('forDeletion', true);
                    var removedChildData = this.getRecordData
                        .call(this, removedChildRecord);
                    data[association.name]
                        .push(removedChildData);
                    record.setDirty();
                }, me);
            }
        }

        // Only return data if it was dirty, new or marked for deletion.
        if (record.dirty || record.phantom || record.get('forDeletion')) {
            return data;
        }
        return null;
    }
});
